#include "ViewGrid.h"
#include "Editor.h"
#include "State.h"

namespace FinalRendering
{
	namespace Editor
	{
		using namespace GxRendering;
		using namespace GxRendering::UI;
		using namespace Editor;
		
		ViewGrid::ViewGrid()
		{
			curView = 0;
			curCapturedView = 0;
			for (int i=0; i<4; i++)
			{
				GLView * v = new GLView();
				Views.Add(v);
				v->OnMouseDown.Bind(this, &ViewGrid::ViewMouseDown);
				v->OnMouseUp.Bind(this, &ViewGrid::ViewMouseUp);
				v->OnMouseMove.Bind(this, &ViewGrid::ViewMouseMove);
				v->OnKeyDown.Bind(this, &ViewGrid::ViewKeyDown);
				v->OnRender.Bind(this, &ViewGrid::ViewRender);
				v->OnResize.Bind(this, &ViewGrid::ViewResize);
				
				v->Parent = this;
				Controls.Add(v);
			}

			OnKeyDown.Bind(this, &ViewGrid::ViewGridKeyDown);

			BindView(0, new View3D());
			BindView(1, new ViewTop());
			BindView(2, new ViewLeft());
			BindView(3, new ViewFront());

			for (int i=0; i<4; i++)
			{
				SceneViews[i]->OnRefreshViews.Bind(this, &ViewGrid::ViewRefreshViews);
				SceneViews[i]->OnGetCurrentScene.Bind(this, &ViewGrid::ViewGetCurrentScene);
				SceneViews[i]->OnGetViewParams.Bind(this, &ViewGrid::ViewGetViewParams);
				SceneViews[i]->OnDrawState.Bind(this, &ViewGrid::ViewDrawState);
			}

			OnMouseWheel.Bind(this, &ViewGrid::ViewMouseWheel);

			AutoSizeViews();
			sizing = 0;
			lstX = lstY = beforeW = beforeH = curX = curY = 0;
		}

		void ViewGrid::ViewRefreshViews()
		{
			WorldEditor->UpdateViews();
		}

		void ViewGrid::ViewDrawState(FinalRendering::Editor::View::ViewType Type, FinalRendering::Editor::View *view)
		{
			switch (Type)
			{
			case View::vtLeft:
				WorldEditor->GetCurrentState()->DrawState_LeftView((ViewLeft *)view);
				break;
			case View::vtTop:
				WorldEditor->GetCurrentState()->DrawState_TopView((ViewTop *)view);
				break;
			case View::vtFront:
				WorldEditor->GetCurrentState()->DrawState_FrontView((ViewFront *)view);
				break;
			case View::vtPerspective:
				WorldEditor->GetCurrentState()->DrawState_3DView((View3D *)view);
				break;
			}
		}

		void ViewGrid::ViewGetCurrentScene(Scene *& scene)
		{
			scene = WorldEditor->Scene.operator ->();
		}

		void ViewGrid::ViewGetViewParams(ViewParam & vp)
		{
			memcpy(vp.GridColor, WorldEditor->Preference.GridColor, sizeof(UI::Color)*MaxGridColorLevels);
			vp.MinScrGridSize = WorldEditor->Preference.MinScrGridSize;
			vp.PerspectiveViewMousePrecision = WorldEditor->Preference.PerspectiveViewMousePrecision;
		}

		void ViewGrid::HandleMessage(const UI_MsgArgs * args)
		{
			if (args->Type == MSG_UI_MOUSEWHEEL)
			{
				ViewMouseWheel(this, *((UIMouseEventArgs *)(args->Data)));
			}
		}

		View * ViewGrid::GetView(UI_Base * viewCtrl)
		{
			for (int i=0; i<4; i++)
			{
				if (Views[i] == viewCtrl)
					return SceneViews[i].operator ->();
			}
			return 0;
		}

		void ViewGrid::ViewRender(UI_Base * sender)
		{
			GetView(sender)->Draw();
		}

		void ViewGrid::ViewResize(UI_Base * sender)
		{
			GLView * v = (GLView *)sender;
			GetView(sender)->SetSize(v->GetWidth(),v->GetHeight());
		}

		void ViewGrid::DoMouseLeave(int X, int Y)
		{
			Container::DoMouseLeave(X,Y);
			curView = 0;
		}

		void ViewGrid::ViewMouseWheel(UI_Base * sender, UIMouseEventArgs & e)
		{
			if (curView)
			{
				curView->Zoom(viewMousePosX, viewMousePosY, (e.Delta<0));
				curView->Refresh();
			}
		}

		void ViewGrid::ViewGridKeyDown(UI_Base * sender, UIKeyEventArgs & e)
		{
			WorldEditor->ProcessLocalAccelerator(e);
		}
		
		void ViewGrid::ViewKeyDown(UI_Base * sender, UIKeyEventArgs & e)
		{
			WorldEditor->GetCurrentState()->KeyDown(GetView(sender), e);
		}

		void ViewGrid::ViewMouseDown(UI_Base * sender, UIMouseEventArgs & e)
		{
			curCapturedView = GetView(sender);
			WorldEditor->GetCurrentState()->MouseDown(GetView(sender), e);
		}

		void ViewGrid::ViewMouseUp(UI_Base * sender, UIMouseEventArgs & e)
		{
			if (curCapturedView)
			{	
				WorldEditor->GetCurrentState()->MouseUp(curCapturedView, e);
				curCapturedView = 0;
			}
		}

		void ViewGrid::ViewMouseMove(UI_Base * sender, UIMouseEventArgs & e)
		{
			curView = GetView(sender);
			
			viewMousePosX = e.X;
			viewMousePosY = e.Y;
			if (curView == curCapturedView || !curCapturedView)
				WorldEditor->GetCurrentState()->MouseMove(GetView(sender), e);
		}

		void ViewGrid::BindView(int viewport, View * view)
		{
			SceneViews[viewport] = view;
			view->SetViewCtrl(Views[viewport], this);
		}

		void ViewGrid::UpdateAllViews()
		{
			for (int i=0; i<4; i++)
				Views[i]->Refresh();
		}

		void ViewGrid::AutoSizeViews()
		{
			int viewWidth = (Width-SplitterSize)/2;
			int viewHeight = (Height-SplitterSize)/2;
			Views[0]->Posit(0,0,viewWidth, viewHeight);
			Views[1]->Posit(viewWidth + SplitterSize, 0, viewWidth, viewHeight);
			Views[2]->Posit(0, viewHeight + SplitterSize, viewWidth, viewHeight);
			Views[3]->Posit(viewWidth + SplitterSize, viewHeight+SplitterSize, viewWidth, viewHeight);
		}

		void ViewGrid::SizeChanged()
		{
			Container::SizeChanged();
			AutoSizeViews();
		}

		void ViewGrid::DoMouseMove(int X, int Y)
		{
			
			X-=Left;
			Y-=Top;
			if (!Visible || !Enabled)
				return;
			int vw = Views[0]->GetWidth();
			int vh = Views[0]->GetHeight();
			int tsizing = 0;
			if (X>vw && X < vw+SplitterSize)
				tsizing = 1;
			if (Y>vh && Y < vh+SplitterSize)
				tsizing += 2;
			if (sizing)
			{
				curX = X;
				curY = Y;
				curX = min(curX, Width-SplitterSize-MinSize);
				curY = min(curY, Height-SplitterSize-MinSize);
				curX = max(MinSize, curX);
				curY = max(MinSize, curY);
			}
			if (sizing)
				tsizing = sizing;
			switch (tsizing)
			{
			case 0:
				Cursor = Arrow;
				break;
			case 1:
				Cursor = SizeWE;
				break;
			case 2:
				Cursor = SizeNS;
				break;
			case 3:
				Cursor = SizeAll;
				break;
			}
			curView = 0;
			if (!sizing)
				Container::DoMouseMove(X,Y);
			else
				Control::DoMouseMove(X,Y);
		}

		void ViewGrid::DoMouseDown(int X, int Y, SHIFTSTATE Shift)
		{
			X-=Left;
			Y-=Top;
			if (!Enabled || !Visible)
				return;
			if (!IsPointInClient(X,Y))
				return;
			int vw, vh;
			vw = Views[0]->GetWidth();
			vh = Views[0]->GetHeight();
			if (X>vw && X < vw+SplitterSize)
				sizing = 1;
			if (Y>vh && Y < vh+SplitterSize)
				sizing += 2;
			lstX = X;
			lstY = Y;
			curX = lstX;
			curY = lstY;
			beforeW = vw;
			beforeH = vh;
			if (!sizing)
				Container::DoMouseDown(X,Y,Shift);
			else
				Control::DoMouseDown(X,Y,Shift);
		}

		void ViewGrid::DoMouseUp(int X, int Y, SHIFTSTATE Shift)
		{
			if (!sizing)
				Container::DoMouseUp(X, Y, Shift);
			else
				Control::DoMouseUp(X,Y,Shift);
			X-=Left;
			Y-=Top;
			int dx = X-lstX;
			int dy = Y-lstY;
			int nw = Views[0]->GetWidth() + dx;
			int nh = Views[0]->GetHeight() + dy;
			nw = min(nw, Width-SplitterSize-MinSize);
			nh = min(nh, Height-SplitterSize-MinSize);
			if (nw < MinSize)
				nw = MinSize;
			if (nh < MinSize)
				nh = MinSize;
			if (sizing == 1 || sizing == 3)
			{
				Views[0]->SetWidth(nw);
				Views[1]->Posit(nw+SplitterSize, 0, max(MinSize, Width-nw-SplitterSize), Views[1]->GetHeight());
				Views[2]->SetWidth(nw);
				Views[3]->Posit(nw+SplitterSize, Views[3]->Top, max(MinSize, Width-nw-SplitterSize), Views[3]->GetHeight());
			}
			if (sizing == 2 || sizing == 3)
			{
				Views[0]->SetHeight(nh);
				Views[1]->SetHeight(nh);
				Views[2]->Top = Views[3]->Top = nh + SplitterSize;
				Views[2]->SetHeight(max(MinSize, Height - nh - SplitterSize));
				Views[3]->SetHeight(Views[2]->GetHeight());
			}
			sizing = 0;
		}

		void ViewGrid::Draw(int absX, int absY)
		{
			Container::Draw(absX, absY);
			absX += Left;
			absY += Top;
			if (!Visible)
				return;
			int dx = curX-lstX;
			int dy = curY-lstY;
			int nw = Views[0]->GetWidth() + dx;
			int nh = Views[0]->GetHeight() + dy;
			glPushMatrix();
			
			glTranslatef((float)absX, (float)absY, 0.0f);
			if (sizing == 1 || sizing == 3)
			{
				Graphics::SolidBrushColor = Color(240,160,0, 180);
				Graphics::FillRectangle(nw, 0, nw+SplitterSize, Height);
			}
			if (sizing == 2 || sizing == 3)
			{
				Graphics::SolidBrushColor = Color(240,160,0, 180);
				Graphics::FillRectangle(0, nh, Width, nh+SplitterSize);
			}

			glPopMatrix();
		}
	}
}